import fs from 'fs';
import type { Request } from 'express'
import path from 'path';
import multer, { type FileFilterCallback, type StorageEngine } from 'multer';
import { v4 as uuidv4 } from 'uuid';
import { imageTyes, videoTypes, docTypes, extensions } from '../constant/upload'

/**
 * 文件上传工具类
 */
export class UploadUtil {
  private static instance: UploadUtil;
  private readonly uploadDir: string;
  
  // 支持的文件类型
  private readonly allowedImageTypes: string[] = Object.keys(imageTyes);
  private readonly allowedVideoTypes: string[] = Object.keys(videoTypes);
  private readonly allowedDocTypes: string[] = Object.keys(docTypes);

  // 文件大小限制 (单位：字节)
  private readonly maxImageSize: number = 5 * 1024 * 1024;      // 5MB
  private readonly maxVideoSize: number = 50 * 1024 * 1024;     // 50MB
  private readonly maxDocSize: number = 10 * 1024 * 1024;       // 10MB

  private constructor() {
    // 创建上传目录
    this.uploadDir = path.join(process.cwd(), 'uploads');
    this.ensureDirectoryExists(this.uploadDir);
    this.ensureDirectoryExists(path.join(this.uploadDir, 'images'));
    this.ensureDirectoryExists(path.join(this.uploadDir, 'videos'));
    this.ensureDirectoryExists(path.join(this.uploadDir, 'docs'));
    this.ensureDirectoryExists(path.join(this.uploadDir, 'temp'));
  }

  /**
   * 获取单例实例
   */
  public static getInstance(): UploadUtil {
    if (!UploadUtil.instance) {
      UploadUtil.instance = new UploadUtil();
    }
    return UploadUtil.instance;
  }

  /**
   * 确保目录存在
   */
  private ensureDirectoryExists(directory: string): void {
    if (!fs.existsSync(directory)) {
      fs.mkdirSync(directory, { recursive: true });
    }
  }

  /**
   * 获取文件扩展名
   */
  private getFileExtension(mimeType: string): string {
    return extensions[mimeType] || '';
  }

  /**
   * 生成唯一文件名
   */
  private generateUniqueFilename(originalname: string, mimeType: string): string {
    const timestamp = Date.now();
    const uuid = uuidv4().substring(0, 8);
    const fileExtension = this.getFileExtension(mimeType);
    const sanitizedOriginalname = path.basename(originalname, path.extname(originalname))
      .replace(/[^a-zA-Z0-9]/g, '_')
      .substring(0, 20);
    
    return `${sanitizedOriginalname}_${timestamp}_${uuid}${fileExtension}`;
  }

  /**
   * 获取文件类型目录
   */
  private getUploadDestination(fileType: string): string {
    if (this.allowedImageTypes.includes(fileType)) {
      return path.join(this.uploadDir, 'images');
    } else if (this.allowedVideoTypes.includes(fileType)) {
      return path.join(this.uploadDir, 'videos');
    } else if (this.allowedDocTypes.includes(fileType)) {
      return path.join(this.uploadDir, 'docs');
    }
    return path.join(this.uploadDir, 'temp');
  }

  /**
   * 创建存储配置
   */
  private createStorage(): StorageEngine {
    return multer.diskStorage({
      destination: (req: Request, file: Express.Multer.File, cb) => {
        const uploadDestination = this.getUploadDestination(file.mimetype);
        cb(null, uploadDestination);
      },
      filename: (req: Request, file: Express.Multer.File, cb) => {
        const uniqueFilename = this.generateUniqueFilename(file.originalname, file.mimetype);
        cb(null, uniqueFilename);
      }
    });
  }

  /**
   * 文件过滤器
   */
  private fileFilter(req: Request, file: Express.Multer.File, cb: FileFilterCallback) {
    const allowedTypes = [
      ...this.allowedImageTypes,
      ...this.allowedVideoTypes,
      ...this.allowedDocTypes
    ];

    if (allowedTypes.includes(file.mimetype)) {
      cb(null, true);
    } else {
      // 创建简化的错误对象，只包含消息
      const error = new Error(`不支持的文件类型: ${file.mimetype}`);
      
      // 重写错误的toString方法，只返回消息
      error.toString = function() {
        return this.message;
      };
      
      cb(error);
    }
  }

  /**
   * 获取上传配置
   */
  public getUploadMiddleware(type: 'image' | 'video' | 'document' | 'any' = 'any', maxCount: number = 1) {
    const storage = this.createStorage();

    let fileSize: number;
    let fileFilter: any;

    // 根据类型设置大小限制和过滤器
    switch (type) {
      case 'image':
        fileSize = this.maxImageSize;
        fileFilter = (req: Request, file: Express.Multer.File, cb: FileFilterCallback) => {
          if (this.allowedImageTypes.includes(file.mimetype)) {
            cb(null, true);
          } else {
            // 创建简化的错误对象，只包含消息
            const error = new Error(`只支持图片文件: ${Object.values(imageTyes).join(' ')}`);
            
            // 重写错误的toString方法，只返回消息
            error.toString = function() {
              return this.message;
            };
            
            cb(error);
          }
        };
        break;
      case 'video':
        fileSize = this.maxVideoSize;
        fileFilter = (req: Request, file: Express.Multer.File, cb: FileFilterCallback) => {
          if (this.allowedVideoTypes.includes(file.mimetype)) {
            cb(null, true);
          } else {
            // 创建简化的错误对象，只包含消息
            const error = new Error(`只支持视频文件: ${Object.values(videoTypes).join(' ')}`);
            
            // 重写错误的toString方法，只返回消息
            error.toString = function() {
              return this.message;
            };
            
            cb(error);
          }
        };
        break;
      case 'document':
        fileSize = this.maxDocSize;
        fileFilter = (req: Request, file: Express.Multer.File, cb: FileFilterCallback) => {
          if (this.allowedDocTypes.includes(file.mimetype)) {
            cb(null, true);
          } else {
            // 创建简化的错误对象，只包含消息
            const error = new Error(`只支持文档文件: ${Object.values(docTypes).join(' ')}`);
            
            // 重写错误的toString方法，只返回消息
            error.toString = function() {
              return this.message;
            };
            
            cb(error);
          }
        };
        break;
      default:
        fileSize = this.maxVideoSize; // 使用最大的限制
        fileFilter = this.fileFilter.bind(this);
        break;
    }

    const multerInstance = multer({
      storage,
      limits: {
        fileSize: fileSize
      },
      fileFilter
    });
    
    // 创建一个自定义的中间件函数来处理文件上传
    return (req: any, res: any, next: any) => {
      // 使用any方法处理所有字段的文件上传
      const upload = multerInstance.any();
      
      // 调用multer中间件处理上传
      upload(req, res, (err) => {
        if (err) {
          // 使用自定义的错误处理
          const simplifiedError = new Error(err.message);
          next(simplifiedError);
          return;
        }
        
        // 将所有表单字段记录到日志中
        // todo
        
        // 继续下一个中间件
        next();
      });
    };
  }

  /**
   * 获取文件URL
   */
  public getFileUrl(filename: string, fileType: string): string {
    let subDir = 'temp';
    
    if (this.allowedImageTypes.includes(fileType)) {
      subDir = 'images';
    } else if (this.allowedVideoTypes.includes(fileType)) {
      subDir = 'videos';
    } else if (this.allowedDocTypes.includes(fileType)) {
      subDir = 'docs';
    }
    
    // 根据实际部署环境设置基础URL
    const baseUrl = process.env.UPLOAD_BASE_URL;
    return `${baseUrl}/uploads/${subDir}/${filename}`;
  }

  /**
   * 格式化上传响应
   */
  public formatResponse(files: Express.Multer.File[]): Array<{url: string, originalname: string, size: number, mimetype: string}> {
    return files.map(file => {
      return ({
        url: this.getFileUrl(file.filename, file.mimetype),
        originalname: file.originalname,
        size: file.size,
        mimetype: file.mimetype
      })
    });
  }
  
  /**
   * 删除文件
   */
  public deleteFile(filePath: string): Promise<void> {
    return new Promise((resolve, reject) => {
      fs.unlink(filePath, (err) => {
        if (err) {
          reject(err);
        } else {
          resolve();
        }
      });
    });
  }
} 